package com.auxgroup.smarthome.enterprise.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auxgroup.smarthome.*;
import com.auxgroup.smarthome.enterpriseapi.EnterpriseApi;
import com.auxgroup.smarthome.enterpriseapi.requestbody.*;
import com.auxgroup.smarthome.enterpriseapi.responsebody.*;
import com.auxgroup.smarthome.syscode.Syscode;
import com.auxgroup.smarthome.utils.common.LOG;
import com.auxgroup.smarthome.web.ApiResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by Toby Lai on 2017/5/8.
 */
@Service
public class DeviceManageService {
    @Autowired
    private ProductService productService;
    @Autowired
    private AuxAnalysisService auxAnalysisService;

    /**
     * 远程控制设备
     * @param pk
     * @param did
     * @param body
     * @return
     */
    public JSONObject controlRemoteDevice(String pk, String did, String body) {
        return EnterpriseApi.DeviceManage.controlRemoteDevice(productService.getToken(pk),pk,did,body);
    }

    /**
     * 通过mac地址获取did和passcode
     * @param pk
     * @param mac
     * @return
     */
    public ApiResponse<DeviceMessage> getDeviceInfo(String pk, String mac) {
        DeviceMessage resultResponse = EnterpriseApi.DeviceManage.getDeviceMessage(productService.getToken(pk), pk, mac);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 搜索WiFI设备
     * @param productKey
     * @param searchDeviceWiFiBody
     * @return
     */
    public ApiResponse<WIFIDeviceList> searchWiFiDevice(String productKey, SearchDeviceWiFiBody searchDeviceWiFiBody) {
        WIFIDeviceList resultResponse= EnterpriseApi.DeviceManage.searchWiFiDevice(productService.getToken(productKey), productKey, searchDeviceWiFiBody);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 去除设备重复数据（平台一个mac可以拿到多条数据，需要拿取最新时间的did正确数据，并且过滤掉其他过时数据）
     * @param productKey
     * @param searchDeviceWiFiBody
     * @return
     */
    public  ApiResponse<List<WIFIDeviceList.WIFIDeviceInfo>> distinctWiFiDeviceData (String productKey, SearchDeviceWiFiBody searchDeviceWiFiBody) {
        ApiResponse<WIFIDeviceList> listApiResponse = searchWiFiDevice(productKey, searchDeviceWiFiBody);
        if(null == listApiResponse.getData()) {
            return ApiResponse.prompt(listApiResponse.getCode()+"", listApiResponse.getMessage());
        }
        List<WIFIDeviceList.WIFIDeviceInfo> deviceInfoList = listApiResponse.getData().getObjects();
        Collections.sort(deviceInfoList, new Comparator<WIFIDeviceList.WIFIDeviceInfo>() {
            @Override
            public int compare(WIFIDeviceList.WIFIDeviceInfo o1, WIFIDeviceList.WIFIDeviceInfo o2) {
                return o1.getCreated_at() == o2.getCreated_at()? 0 : o1.getCreated_at() < o2.getCreated_at()? 1: -1 ;
            }
        });
        Set<WIFIDeviceList.WIFIDeviceInfo> set = new LinkedHashSet();
        for(Iterator<WIFIDeviceList.WIFIDeviceInfo> it = deviceInfoList.iterator(); it.hasNext(); ) {
            WIFIDeviceList.WIFIDeviceInfo deviceInfo = it.next();
            if(!set.contains(deviceInfo)) {
                set.add(deviceInfo);
            }
        }
        deviceInfoList.clear();
        deviceInfoList.addAll(set);
        return ApiResponse.ok(deviceInfoList);
    }

    /**
     * 搜索l蓝牙设备
     * @param productKey
     * @param searchDeviceBtBody
     * @return
     */
    public ApiResponse<BTDeviceList> searchBTDevice(String productKey, SearchDeviceBtBody searchDeviceBtBody) {
        BTDeviceList resultResponse= EnterpriseApi.DeviceManage.searchBtDevice(productService.getToken(productKey), productKey, searchDeviceBtBody);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 拿到所有wifi设备的did
     *
     * @param productKey
     * @return
     */
    public Set<String> getAllDeviceDids(String productKey) {
        Set<String> allDids = new HashSet<String>();
        ApiResponse<WIFIDeviceList> allDeviceList = searchWiFiDevice(productKey, null);
        if (StringUtils.isNotBlank(allDeviceList.getData().getError_code())) {
            return null;
        }
        List<WIFIDeviceList.WIFIDeviceInfo> allDeviceListObjects = allDeviceList.getData().getObjects();
        for (Iterator<WIFIDeviceList.WIFIDeviceInfo> iterator = allDeviceListObjects.iterator(); iterator.hasNext(); ) {
            WIFIDeviceList.WIFIDeviceInfo deviceInfoDetail = iterator.next();
            if (StringUtils.isNotBlank(deviceInfoDetail.getDid())) {
                allDids.add(deviceInfoDetail.getDid());
            }
        }
        return allDids;
    }

    /**
     * 通过mac获取设备详情
     * @param productKey
     * @param mac
     * @return
     */
    public WIFIDeviceList.WIFIDeviceInfo getDeviceDetailInfo(String productKey, String mac) {
        SearchDeviceWiFiBody searchDeviceBody = new SearchDeviceWiFiBody();
        searchDeviceBody.setType("mac");
        searchDeviceBody.setVal(mac);
        WIFIDeviceList deviceDetailList = EnterpriseApi.DeviceManage.searchWiFiDevice(productService.getToken(productKey), productKey, searchDeviceBody);
        if(StringUtils.isNotEmpty(deviceDetailList.getError_code())) {
            return null;
        }
        if(deviceDetailList.getObjects().size() > 0) {
            return deviceDetailList.getObjects().get(0);
        }
        return null;
    }

    /**
     * 设备上下线数据
     * @param pk
     * @param did
     * @param body
     * @return
     */
    public ApiResponse<DeviceOnoffline> getDeviceOnoffData(String pk, String did, DevicesOnlineDataBody body){
        DeviceOnoffline resultResponse = EnterpriseApi.DeviceManage.getDeviceOnofflineData(productService.getToken(pk), pk, did, body);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 获得某一台设备（两天以内）数据点值 的历史数据
     * @param pk
     * @param did
     * @param body
     * @return
     */
    public ApiResponse<DeviceAttrsData> getDeviceHistoryData(String pk, String did, DeviceAttrsDataBody body) {
        DeviceAttrsData resultResponse = EnterpriseApi.DeviceManage.getDeviceHistoryData(productService.getToken(pk), pk, did, body);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    public ApiResponse<Map<Integer,Integer>> getAuxDeviceHistoryData(String pk, String did, DeviceAttrsDataBody body,String attr){
        Map<Integer,Integer>  historyDataMap = new HashMap<>();
        DeviceAttrsData resultResponse = EnterpriseApi.DeviceManage.getDeviceHistoryData(productService.getToken(pk), pk, did, body);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        List<DeviceAttrsData.AttrsValueData> objects = resultResponse.getObjects();
        if (objects==null || objects.size()==0){
            return ApiResponse.prompt(Syscode.NOT_CONTENT);
        }
        objects.stream().forEach(attrsValueData -> {
            int ts = attrsValueData.getTs();
            JSONObject attrsJson = attrsValueData.getAttrs();
            Object valueobj = attrsJson.get(attr);
            int value = valueobj==null ? 0 : Integer.parseInt(valueobj.toString());
            historyDataMap.put(ts,value);
        });
        return ApiResponse.ok(historyDataMap);
    }

    /**
     * 获取设备最新状态
     * @param pk
     * @param did
     * @return
     */
    public ApiResponse<DeviceAttrsData> getLastestDevice(String pk, String did) {
        DeviceAttrsDataBody deviceAttrsDataBody = new DeviceAttrsDataBody().firstData();
        return getDeviceHistoryData(pk, did, deviceAttrsDataBody);
    }

    /**
     * 获取单元机设备最新状态
     * @param pk
     * @param did
     * @return key: 设备数据点  value:对应数据点的值
     */
    public ApiResponse<Map<String,String>> getLastestDatapointDeviceInfo(String pk,String did){
        return getLastestDatapointDeviceInfoBySrcAndCmd(pk, did, "0700", 1);
    }

    /**
     * 获取多联机设备最新状态
     * @param pk
     * @param did
     * @return
     */
    public ApiResponse<Map<String,String>> getLastestDatapointDeviceInfoWithMultiSplit(String pk,String did){
        return getLastestDatapointDeviceInfoBySrcAndCmd(pk, did, "0680", 0);
    }

    /**
     *  获取设备的最新状态
     *  <p>1、cmd=0700, src=1 用于获取单元机设备最新状态</p>
     *  <p>1、cmd=0680, src=0 用于获取多联机设备最新状态</p>
     *  <pre>普通控制：0（CMD：0680）
     *  普通控制采集：1（CMD：0700）
     *  状态采集：2（CMD：0700）
     *  睡眠曲线控制：3（CMD：0680）
     *  睡眠曲线采集：4（CMD：0700）
     *  高级控制：5 （峰谷电等）（CMD：0680）</pre>
     * @param pk 产品key
     * @param did 设备did
     * @param cmd
     * @param src
     * @return
     */
    public ApiResponse<Map<String,String>> getLastestDatapointDeviceInfoBySrcAndCmd(String pk,String did, String cmd, int src){
        ApiResponse<JSONObject> apiResponse = auxAnalysisService.getLatestDataByCmdAndSrc(pk, did, cmd, src);
        if (!apiResponse.isNotErrorCode()){
            return ApiResponse.prompt(apiResponse.getCode(),apiResponse.getMessage());
        }
        JSONObject attrs = apiResponse.getData().getJSONObject("data").getJSONObject("data");
        if (attrs == null){
            return ApiResponse.prompt(Syscode.NOT_CONTENT);
        }
        Set<Map.Entry<String, Object>> entries = attrs.entrySet();
        Map<String,String> datapointMap = new HashMap<>();
        for(Iterator<Map.Entry<String, Object>> iterator = entries.iterator();iterator.hasNext();){
            Map.Entry<String, Object> next = iterator.next();
            datapointMap.put(next.getKey(),next.getValue().toString());
        }
        return ApiResponse.ok(datapointMap);
    }

    /**
     * 当前是否为制热制冷模式
     * @param pk
     * @param did
     * @return true: 是 ； false:不是
     */
    public boolean isHotAndColdMode(String pk,String did){
        ApiResponse<Map<String, String>> apiResponse = getLastestDatapointDeviceInfo(pk, did);
        if (apiResponse==null && !apiResponse.isNotErrorCode()){
            throw new IllegalArgumentException("judge isHotAndColdMode error == pk:"+pk + "did:"+pk);
        }
        Map<String, String> data = apiResponse.getData();
        String model = data.get("air_con_func");
        int func = Integer.parseInt(model);
        return func==1 || func==4;
    }

    /**
     * 普通远程控制 此方法只能适用于奥克斯空调
     * @param pk
     * @param did
     * @param changeDataPointMap 控制操作而改变的数据点
     * @return
     */
    public ApiResponse commonRemoteControlDevice(String pk,String did,Map<String,String> changeDataPointMap){
        ApiResponse<Map<String, String>> lastestDatapointDeviceInfo = getLastestDatapointDeviceInfo(pk, did);
        Map<String, String> lastestDatapointDeviceInfoData = lastestDatapointDeviceInfo.getData();
        //可能存在并发，特别是定时控制任务这一块，故一定要保持顺序，否则生成的原始指令raw可能会出错。
        Map<String, String> controlDatapointValuesMap = new LinkedHashMap<String, String>();
        DatapointControlEnum[] values = DatapointControlEnum.values();
        Arrays.stream(values).forEachOrdered(datapointControlEnum -> {
            String name = datapointControlEnum.getName();
            String datapointValue = lastestDatapointDeviceInfoData.get(name);
            controlDatapointValuesMap.put(name,datapointValue);
        });
        for(Iterator<Map.Entry<String, String>> iterator = changeDataPointMap.entrySet().iterator();
            iterator.hasNext();){
            Map.Entry<String, String> next = iterator.next();
            controlDatapointValuesMap.put(next.getKey(),next.getValue());
        }
        int[] raw = DatapointConvertUtils.getA1ControlRaw(controlDatapointValuesMap);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("raw",raw);
        JSONObject controlResult = controlRemoteDevice(pk, did, jsonObject.toJSONString());
        StringBuffer logbuffer = new StringBuffer("家用空调控制指令-》");
        logbuffer.append("pk:").append(pk)
                .append("--did:").append(did)
                .append("--raw:").append(jsonObject.toJSONString())
                .append("--result:").append(controlResult);
        LOG.info(this, logbuffer.toString());
        return ApiResponse.prompt(Syscode.SC_OK);
    }


    /**
     * 商用空调 控制 此方法只能适用于奥克斯空调
     * @param pk
     * @param did
     * @param businessDataPointMap 控制操作而改变的数据点
     * @return
     */
    public ApiResponse businessRemoteControlDevice(String pk,String did, int dst, Map<String,String> businessDataPointMap){
        ApiResponse<Map<String, String>> lastestDatapointDeviceInfo = getLastestDatapointDeviceInfoWithMultiSplit(pk, did);
        Map<String, String> lastestDatapointDeviceInfoData = lastestDatapointDeviceInfo.getData();
        //可能存在并发，特别是定时控制任务这一块，故一定要保持顺序，否则生成的原始指令raw可能会出错。
        Map<String, String> controlDatapointValuesMap = new LinkedHashMap<String, String>();
        BusinessDatapointControlEnum[] values = BusinessDatapointControlEnum.values();
        Arrays.stream(values)
        .forEachOrdered(
            datapointControlEnum -> {
              String name = datapointControlEnum.getName();
              String datapointValue = lastestDatapointDeviceInfoData.get(name);
              controlDatapointValuesMap.put(name, datapointValue);
            });
        for(Iterator<Map.Entry<String, String>> iterator = businessDataPointMap.entrySet().iterator();
            iterator.hasNext();){
            Map.Entry<String, String> next = iterator.next();
            controlDatapointValuesMap.put(next.getKey(),next.getValue());
        }
        int[] raw = BusinessDatapointConvertUtils.getBusinessAControlRaw(dst, controlDatapointValuesMap);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("raw",raw);
        JSONObject controlResult = controlRemoteDevice(pk, did, jsonObject.toJSONString());
        StringBuffer logbuffer = new StringBuffer("商用空调控制指令-》");
        logbuffer.append("pk:").append(pk)
                .append("--did:").append(did)
                .append("--raw:").append(jsonObject.toJSONString())
                .append("--result:").append(controlResult);
        LOG.info(this, logbuffer.toString());
        return ApiResponse.prompt(Syscode.SC_OK);
    }

    /**
     * 睡眠DIY控制(只适用于奥克斯家用空调)
     * @param pk
     * @param did
     * @param sleepDataPointMap
     * @return
     */
    public ApiResponse sleepDiyRemoteControl(String pk,String did,String inputMode,LinkedHashMap<String,String> sleepDataPointMap){
        //增加判断，如果当前模式不是制冷和制热，并且当前模式和设置模式不一致，则不发送
        ApiResponse<Map<String, String>> lastestDatapointDeviceInfo = getLastestDatapointDeviceInfo(pk, did);
        Map<String, String> lastestDatapointDeviceInfoData = lastestDatapointDeviceInfo.getData();
        String mode = lastestDatapointDeviceInfoData.get(BusinessDatapointControlEnum.AIR_CON_FUNC.getName());
        if((!"1".equals(mode) && !"4".equals(mode)) || !mode.equals(inputMode)){
            LOG.info(this, "睡眠diy,did:"+did+"下发失败:当前模式与设置模式不一致");
            return ApiResponse.prompt(Syscode.FAIL);
        }

        int[] raw = SleepDiyDatapointConvertUtils.getA13ControlRaw(sleepDataPointMap);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("raw",raw);
        JSONObject controlResult = controlRemoteDevice(pk, did, jsonObject.toJSONString());
        StringBuffer logbuffer = new StringBuffer("睡眠DIY控制指令-》");
        logbuffer.append("pk:").append(pk)
                .append("--did:").append(did)
                .append("--raw:").append(jsonObject.toJSONString())
                .append("--result:").append(controlResult);
        LOG.info(this, logbuffer.toString());
        return ApiResponse.prompt(Syscode.SC_OK);
    }

    /**
     * 关闭睡眠DIY
     * @param pk
     * @param did
     * @return
     */
    public ApiResponse closeSleepDiyRemoteControl(String pk,String did){
        Map<String,String> changeDataPointMap = new HashMap<>();
        changeDataPointMap.put(DatapointControlEnum.SLEEP_DIY.getName(),"0");
        commonRemoteControlDevice(pk,did,changeDataPointMap);
        return ApiResponse.prompt(Syscode.SC_OK);
    }

    /**
     * 智能用电预留位填充
     * @param datapointMap
     */
    private static void obligateFill(Map<String, String> datapointMap) {
        datapointMap.put("obligate_10", "0");
        datapointMap.put("obligate_9", "0");
        datapointMap.put("obligate_8", "0");
        datapointMap.put("obligate_7", "0");
    }

    /**
     * 智能用电、峰谷节点 控制 （只适用与家用空调）
     * @param pk
     * @param did
     * @param electricalCurveDataPointMap
     * @return
     */
    public ApiResponse electricalCurveRemoteControl(String pk,String did,Map<String,String> electricalCurveDataPointMap){
        // 预留位填充
        obligateFill(electricalCurveDataPointMap);
        //可能存在并发，特别是定时控制任务这一块，故一定要保持顺序，否则生成的原始指令raw可能会出错。
        Map<String, String> controlDatapointValuesMap = new LinkedHashMap<String, String>();
        ElectricalCurveControlEnum[] values = ElectricalCurveControlEnum.values();
        Arrays.stream(values).forEachOrdered(datapointControlEnum -> {
            String name = datapointControlEnum.getName();
            String datapointValue = electricalCurveDataPointMap.get(name);
            controlDatapointValuesMap.put(name,datapointValue);
        });
        int[] raw = ElectricalCurveConvertUtils.getA17ControlRaw(controlDatapointValuesMap);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("raw",raw);
        JSONObject resultJson = controlRemoteDevice(pk, did, jsonObject.toJSONString());
        StringBuffer logbuffer = new StringBuffer("智能用电&峰谷节电控制指令-》");
        logbuffer.append("pk:").append(pk)
                .append("--did:").append(did)
                .append("--raw:").append(jsonObject.toJSONString())
                .append("--result:").append(resultJson);
        LOG.info("", logbuffer.toString());
        return ApiResponse.prompt(Syscode.SC_OK);
    }

    /**
     * 峰谷节电，智能用电的控制
     * @param pk
     * @param did
     * @param peakVallyStatus 波峰波谷开启关闭的状态
     * @param smartElectricityStatus 智能用电是否有效的状态
     * @param electricityValue 用电百分比的值
     */
    public void controlPeakValleyAndSmartElectricity(String pk,String did,Integer peakVallyStatus,
                                                     Integer smartElectricityStatus,Integer electricityValue){
        Map<String,String> controlDatapointValuesMap = new HashMap<>();
        controlDatapointValuesMap.put("peak_to_valley_power",peakVallyStatus.toString());
        controlDatapointValuesMap.put("intelligent_electricity",smartElectricityStatus.toString());
        controlDatapointValuesMap.put("percentage_of_intelligent_electricity",electricityValue.toString());
        ApiResponse apiResponse = electricalCurveRemoteControl(pk,did,controlDatapointValuesMap);
        LOG.info(this, JSON.toJSONString(apiResponse));
    }







    /**
     * 设备上下线记录（实时）
     按 ts 降序排序。
     设备的心跳统计信息，在设备上下线记录的 Payload 中。
     设备上线记录中，payload 记录了设备设备指定的心跳时间间隔（KeepAlive），单位为秒，此 KeepAlive 的值等于设备上传的心跳时间间隔再加上5秒
     设备下线记录中，payload 记录了设备的在线时长（duration），以及在线时发送的心跳次数（heartbeat/count），相邻两个心跳的最大间隔时间（heartbeat/max），最小间隔时间（heartbeat/min），平均间隔时间（heartbeat/avg）, 最后一次收到心跳时刻与下线时刻的间隔时间（heartbeat/last），单位为秒
     心跳的间隔时间，为m2m收到第n次心跳的时间点（时间戳）与第n-1次心跳的时间点（时间戳）之差，其中n >= 2；当n < 2时，max，min，avg的值固定为0
     max，min：计算客户端从接到第一次心跳开始，到最后一次接到心跳为止的时间段内，相邻两个心跳时间差的最大，最小值；
     avg：客户端与云端建立链接开始，到最后一次接到心跳为止的时间段，除以心跳次数；
     设备下线记录中，payload记录了设备的下线原因（reason），说明各种reason的意义：
     mqtt_disconnect：设备主动断开与mqtt的连接
     no_heartbeat：m2m在KeepAlive时段内，没有收到设备心跳
     tcp_closed：设备主动断开tcp连接
     ssl_closed：设备主动断开ssl连接
     offline_force：设备重复上线，原有的连接断开
     offline_reset：设备注销，断开连接
     offline_exception：异常断开连接
     offline_sending_density_overflow：客户端发送信息的频率过大，断开链接
     offline_sending_data_size_overflow：客户端发送信息的流量过大，断开链接
     * @param pk
     * @param did
     * @param devicesOnlineDataBody
     * @return
     */
    public ApiResponse<DeviceOnoffline> getOnOfflineData(String pk, String did, DevicesOnlineDataBody devicesOnlineDataBody) {
        DeviceOnoffline resultResponse = EnterpriseApi.DeviceManage.getDeviceOnofflineData(productService.getToken(pk), pk, did, devicesOnlineDataBody);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 设备通信日志（实时）
     按 ts 降序排序。
     payload 为二进制进行 base64 编码后的结果。
     0.4.2.1 start_ts 和 end_ts不填，默认查询过去到现在两天以内的通信日志记录
     0.4.2.1 start_ts与end_ts之间的间隔秒必须在两天范围以内
     0.4.2.1 增加sort排序，默认为降序，asc代表升序，desc代表降序
     * @param pk
     * @return
     */
    public ApiResponse<DeviceCmd> getDeviceCmd(String pk, String did, DeviceCmdBody deviceCmdBody) {
        DeviceCmd resultResponse = EnterpriseApi.DeviceManage.getDeviceCmd(productService.getToken(pk), pk, did, deviceCmdBody);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 获取设备地理位置分布（实时）
     * @param pk
     * @param devicesLocationsBody
     * @return
     */
    public ApiResponse<DevicesLocations> getDeviceLocation(String pk, DevicesLocationsBody devicesLocationsBody) {
        DevicesLocations resultResponse = EnterpriseApi.DeviceManage.getDeviceLocation(productService.getToken(pk), pk, devicesLocationsBody);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 获取设备详细 （主要是 是否在线）
     *
     * @param pk
     * @param mac
     * @return
     */
    public ApiResponse<DeviceDetails> getDeviceDetails(String pk, String mac) {
        DeviceDetails resultResponse = EnterpriseApi.DeviceManage.getDeviceDetails(productService.getToken(pk), pk, mac);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 绑定设备
     *
     * @param pk
     * @param body
     * @return
     */
    public ApiResponse<BindAndUnbindStatus> bindDevices(String pk, BindAndUnbindBody body) {
        BindAndUnbindStatus resultResponse = EnterpriseApi.DeviceManage.bindDevices(productService.getToken(pk), pk, body);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 解绑设备
     *
     * @param pk
     * @param body
     * @return
     */
    public ApiResponse<BindAndUnbindStatus> unbindDevices(String pk, BindAndUnbindBody body) {
        BindAndUnbindStatus resultResponse = EnterpriseApi.DeviceManage.unbindDevices(productService.getToken(pk), pk, body);
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        LOG.info(this, "企业API解绑设备结果："+resultResponse);
        return ApiResponse.ok(resultResponse);
    }

    /**
     * 获取中控设备的子设备设备列表
     * @param pk
     * @param did
     * @param limit
     * @param skip
     * @return
     */
    public ApiResponse<ControlSlave> getControlSlaveList(String pk, String did, Integer limit, Integer skip) {
        ControlSlave resultResponse = EnterpriseApi.DeviceManage.getControlSlaveList(productService.getToken(pk), pk, did, String.valueOf(limit), String.valueOf(skip));
        if(StringUtils.isNotEmpty(resultResponse.getError_code())) {
            return ApiResponse.prompt(resultResponse.getError_code(), resultResponse.getError_message());
        }
        return ApiResponse.ok(resultResponse);
    }
}
